home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / c / cflow.lha / cflow-2.0 / prcc.c < prev    next >
C/C++ Source or Header  |  1999-02-20  |  28KB  |  1,158 lines

  1. /* prcc.c: This file contains the parser for the calls command. */
  2.  
  3. /* This program is a modification of Steve Kirkendall's ctags(1) which
  4.  * is distributed as part of his vi-clone elvis.  It is contributed
  5.  * to the public domain by Andrew Moore of Talke Studio. */
  6.  
  7. static char *id = "$Id: prcc.c,v 1.4 1995/02/16 05:35:57 leisner Exp $";
  8. static char *version = "$Revision: 1.4 $";
  9.  
  10. #include <stdio.h>
  11. #include <ctype.h>
  12.  
  13. #include <string.h>
  14. #include <stdlib.h>
  15. #include <assert.h>
  16.  
  17. typedef enum { FALSE=0, TRUE=1 } BOOLEAN;
  18.  
  19. #ifndef PATH_MAX
  20. #define PATH_MAX 1024
  21. #endif
  22.  
  23.  
  24. typedef struct ns {        /* name structure */
  25.     struct ns *next;
  26.     char *name;
  27. } name_t;
  28.  
  29. /* maximum identify length... */
  30. #ifndef NAME_MAX
  31. #define NAME_MAX    32
  32. #endif
  33. #define TAG_MAX (NAME_MAX * 2 + PATH_MAX + 20)    /* maximum tag length */
  34. #define TAG_STACKSIZE 20    /* tag stack size */
  35.  
  36. #include     "prcc.prototypes.h"
  37.  
  38.  
  39.  
  40. /* The following boolean variables are set according to command line flags */
  41. static int incl_vars;        /* -v include variables */
  42. static int gnu_keywords;    /* -g deletes GNU keywords */
  43. static int posix_keywords;    /* -p deletes posix keywords */
  44. static int ansi_keywords;    /* -a deletes ansi keywords */
  45.  
  46. /* These are used for reading a source file.  It keeps track of line numbers */
  47. static char file_name[PATH_MAX];    /* name of the current file */
  48. static FILE *file_fp;        /* stream used for reading the file */
  49. static long file_lnum;        /* line number in the current file */
  50. static int file_afternl;    /* boolean: was previous character a newline? */
  51. static int file_prevch;        /* a single character that was ungotten */
  52.  
  53.  
  54. static char *progname;
  55.  
  56. static char lex_name[NAME_MAX+1];    /* the name of a "NAME" token */
  57.  
  58. static void usage(void)
  59. {
  60.     fprintf(stderr, "%s [-akgvp] [files]\n", progname);
  61.     fprintf(stderr, "\t-a\tdelete ansi keywords\n");
  62.     fprintf(stderr, "\t-g\tdelete gnu keywords\n");
  63.     fprintf(stderr, "\t-p\tdelete posix keywords\n");
  64.     fprintf(stderr, "\t-v\tinclude variables\n");
  65.     fprintf(stderr, "\t-k\tprint names to stdout and exit\n");
  66.     exit(2);
  67. }
  68.  
  69. void main(int argc, char **argv)
  70. {
  71.     extern int optind;
  72.     extern char *optarg;
  73.     int c;
  74.  
  75.     progname = argv[0];
  76.  
  77.     /* parse the option flags */
  78.     while (1) {
  79.         c = getopt(argc, argv, "pakgv");
  80.         if (c == -1)
  81.             break;
  82.         switch (c) {
  83.             case 'k':
  84.                 show_all_lists();
  85.                 exit(1);
  86.             case 'g':
  87.                 gnu_keywords = TRUE;
  88.                 break;
  89.             case 'a':
  90.                 ansi_keywords = TRUE;
  91.                 break;
  92.             case 'p':
  93.                 posix_keywords = TRUE;
  94.                 break;
  95.             case 'v':
  96.                 incl_vars = TRUE;
  97.                 break;
  98.             default:
  99.                 usage();
  100.         }
  101.     }
  102.  
  103.     argv += optind;
  104.     do {
  105.         /* can't open file */
  106.         if (!cpp_open(*argv ? *argv++ : "-")) {
  107.             break;    /* least the error goes unnoticed */
  108.         }
  109.         /* initialize name lists */
  110.         per_file_init();
  111.  
  112.         /* process file */
  113.         ctags();
  114.  
  115.         /* free name lists */
  116.         per_file_cleanup();
  117.     } while (*argv);
  118.  
  119.     /* flush tag stack */
  120.     maketag(0, 0);
  121.     exit(0);
  122.     /*NOTREACHED */
  123. }
  124.  
  125.  
  126. /* -------------------------------------------------------------------------- */
  127. /* This is the parser.  It locates tag candidates, and then decides
  128.  * whether to generate a tag for them. */
  129.  
  130. /* These are C tokens after which a parenthesis is valid
  131.  * which would otherwise be tagged as function names. The
  132.  * reserved words which are not listed are break, continue,
  133.  * default and goto.  */
  134. static char *reserved[] =
  135. {
  136.     "extern", 
  137.     "auto", "case", "char", "const", "do", "double", "else",
  138.     "entry", "enum", "extern", "float", "for", 
  139.     "if", "int", "long", "register", "return", "short",
  140.     "signed", "sizeof", "static", "struct", "switch", "typedef",
  141.     "union", "unsigned", "void", "volatile", "while",
  142.     0
  143. };
  144.  
  145. static char *gnu_reserved[] =
  146. {
  147.     "asm", "__asm__",
  148.     "__attribute__",    
  149.     "__complex__",
  150.     "__real__",
  151.     "__imag__",
  152.     "__const__",
  153.     "__extension__",
  154.     "inline", "__inline__",
  155.     "__label__",
  156.     "__signed__",
  157.     "typeof", "__typeof__",
  158.     "__volatile__",
  159.     0
  160. };
  161.  
  162. /* this also includes bsd'isms...not really exact, but
  163.  * good enough 
  164.  */
  165. static char *posix_reserved[] =
  166. {
  167.     "access", "alarm", "brk", "chdir",
  168.     "chmod", "chown", "fchmod",
  169.     "close", "closedir",
  170.     "creat",
  171.     "ctermid", "cuserid",
  172.     "dup", "dup2",
  173.     "execl", "execle", "execlp", "execlpe",
  174.     "execv", "execve", "execvp", "execvpe",
  175.     "_exit",
  176.     "errno",
  177.     "fdopen",
  178.     "fstat",
  179.     "fork",
  180.     "getcwd", "getegid", "getenv", "geteuid", "getgid", "getgrent",
  181.     "getprgid", "getgrnam", "getlogin", "getpass", "getpgrp",
  182.     "getpid", "getppid", "getpwent", "getpwnam", "getpwuid", "getuid",
  183.     "ioctl",
  184.     "isatty",
  185.     "kill",
  186.     "link", "lseek", "mkdir", "mkfifo", "mknod",
  187.     "read",
  188.     "open",
  189.     "opendir", "pause", "pipe", "readdir",
  190.     "perror",
  191.     "popen", "pclose",
  192.     "rmdir", "rename", "unlink",
  193.     "sbrk", "setuid", "signal", "sleep", "stat",
  194.     "time", "times", "ttyname", "umask", "uname",
  195.     "unlink",
  196.     "ustat", "utime",
  197.     "sigaction",
  198.     "write",
  199.     0
  200. };
  201.  
  202. static char *ansi_reserved[] =
  203. {
  204.     "atexit",
  205.     "exit",
  206.  
  207.     /* stdio function */
  208.     "fflush",
  209.     "fopen",
  210.     "fclose",
  211.     "fread", "fwrite",
  212.     "fprintf",
  213.     "fgets",
  214.     "fputs",
  215.     "fscanf",
  216.     "printf",
  217.     "putchar",
  218.     "putc", "fputc", "puts",
  219.     "scanf",
  220.     "signal",
  221.     "system",
  222.     "sscanf",
  223.     "sprintf",
  224.     "vfprintf",
  225.     "vprintf",
  226.  
  227.     /* string functions */
  228.     "index", "rindex", "bcopy",
  229.     "strcat", "strncat", "strlen", "strcpy", "strncpy",
  230.     "strchr", "strrchr",
  231.     "strdup", "strcmp", "strncmp", "strncasecmp", "strcasecmp",
  232.     /* math functions */
  233.     /* memory functions */
  234.     "malloc", "realloc", "calloc", "free",
  235.     "memcpy", "memmove",
  236.     0
  237.  
  238.  
  239. };
  240.  
  241. /* list of reserved words */
  242. static name_t *keyword;
  243.  
  244. enum lex_tokens {        /* token types */
  245.     DELETED,
  246.     BODY,
  247.     BODYEND,
  248.     LBRACKET,
  249.     RBRACKET,
  250.     ARGS,
  251.     ARGSEND,
  252.     COMMA,
  253.     SEMICOLON,
  254.     COLON,
  255.     KSTATIC,
  256.     KEXTERN,
  257.     KSTRUCT,
  258.     KTYPEDEF,
  259.     TYPESPEC,
  260.     NAME,
  261.     STRUREF,
  262.     ASSIGN,
  263.     OPERATOR
  264. };
  265.  
  266.  
  267. /* Basic types for initializing type specifier list */
  268. static char *type[] =
  269. {
  270.     "char", "double", "enum", "float", "int", "long", "short",
  271.     "signed", "struct", "union", "unsigned", "void",
  272.     0
  273. };
  274.  
  275. /* A type specifer list prevents declarations such as: int (*func())();
  276.  * from being parsed as calls */
  277. static name_t *type_specifier;
  278.  
  279. /* A functions-previously-defined list assures that functions are defined
  280.  * only once. */
  281. static name_t *func_defined;
  282.  
  283. /* A functions/variables-previously-called list assures that calls are
  284.  * printed only once per function definition. */
  285. static name_t *per_func_ref;
  286.  
  287. /* Three variables lists to track global/extern/local variable
  288.  * declarations. */
  289. static name_t *variable;
  290. static name_t *extern_var;
  291. static name_t *per_func_var;
  292.  
  293. static int gotname;        /* boolean: does lex_name contain a tag candidate? */
  294. static int blockno;        /* marks the extent of a scope */
  295. static int listno;        /* marks the extent of a parameter list */
  296. static int func_seen;        /* boolean: true if function is redefined */
  297.  
  298. /* This function parses a source file and prints function calls. */
  299. static void ctags(void)
  300. {
  301.     int initializer = FALSE;    /* initialization list */
  302.     int prev;        /* the previous token from the source file */
  303.     int token = SEMICOLON;    /* the current token from the source file */
  304.     int scope = 0;        /* normally 0, but could be KTYPEDEF or KSTATIC */
  305.     int scopeno = 0;    /* block number upon entering a scope */
  306.     int structdeclr = FALSE;    /* struct/union/enum declaration */
  307.     int structno = 0;    /* block number upon entering struct */
  308.     int typedeclr = FALSE;    /* type declaration */
  309.  
  310.     /* reset */
  311.     gotname = FALSE;
  312.  
  313.     /* parse until the end of the file */
  314.     while (prev = token, (token = lex_gettoken()) != EOF) {
  315.         /* scope keyword? */
  316.         if (token == KTYPEDEF || token == KSTATIC || token == KEXTERN) {
  317.             /* set scope */
  318.             scope = token;
  319.             scopeno = blockno;
  320.             gotname = FALSE;
  321.             continue;
  322.         }
  323.         /* type declaration */
  324.         if (token == KSTRUCT || token == TYPESPEC) {
  325.             typedeclr = TRUE;
  326.             gotname = FALSE;
  327.             continue;
  328.         }
  329.         /* (not STRUREF) NAME: NAME is tag? */
  330.         if (token == NAME && prev != STRUREF && prev != KSTRUCT) {
  331.             gotname = TRUE;
  332.             continue;
  333.         }
  334.         /* ASSIGN BODY: initilizer */
  335.         if (token == BODY && prev == ASSIGN) {
  336.             gotname = FALSE;
  337.  
  338.             /* global */
  339.             if (blockno == 1) {
  340.                 initializer = TRUE;
  341.             }
  342.             continue;
  343.         }
  344.         /* [NAME] BODY (no ARGS): struct declr [NAME is a struct tag] */
  345.         if (token == BODY && prev != ARGS) {
  346.             gotname =